package com.bci.internal.engine.bcibpmengine.utils;


import org.apache.commons.validator.routines.DomainValidator;
import org.apache.commons.validator.routines.EmailValidator;
import org.apache.commons.validator.routines.UrlValidator;

import java.util.regex.Pattern;

/**
 * Constraint Validation Utils
 * @author jzwu
 * @since 2021/4/4 0004
 */
public abstract class BCValidationUtils {

    private final static String CHINESE_ALPHABET_DIGIT_REGEX = "^[\\u4E00-\\u9FA5\\uF900-\\uFA2Da-zA-Z0-9]+$";
    private final static Pattern CHINESE_ALPHABET_DIGIT_PATTERN = Pattern.compile(CHINESE_ALPHABET_DIGIT_REGEX);

    private final static String INLAND_PHONE_REGEX = "^((13[0-9])|(15[^4])|(18[0-9])|(17[0-8])|(147))\\d{8}$";
    private final static Pattern INLAND_PHONE_PATTERN = Pattern.compile(INLAND_PHONE_REGEX);

    private final static String HK_PHONE_REGEX = "^([5689])\\d{7}$";
    private final static Pattern HK_PHONE_PATTERN = Pattern.compile(HK_PHONE_REGEX);

    private final static String MAC_ADDRESS_REGEX = "^([A-Fa-f0-9]{2}[-,:]){5}[A-Fa-f0-9]{2}";
    private final static Pattern MAC_ADDRESS_PATTERN = Pattern.compile(MAC_ADDRESS_REGEX);

    private final static String IP_ADDRESS_REGEX = "^(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])$";
    private final static Pattern IP_ADDRESS_PATTERN = Pattern.compile(IP_ADDRESS_REGEX);

    private final static String IDCARD_CN_REGEX = "^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$";
    private final static Pattern IDCARD_CN_PATTERN = Pattern.compile(IDCARD_CN_REGEX);

    private final static String COLOR_STRING_REGEX = "^#[A-Fa-f0-9]{6}|#[A-Fa-f0-9]{8}";
    private final static Pattern COLOR_STRING_PATTERN = Pattern.compile(COLOR_STRING_REGEX);

    private final static String VIDEO_FILENAME_REGEX = "^.*?\\.(?i)(mp4|ts|3gp|mpg|mpeg|mpe|dat|vob|avi|wmv|asf|flv|f4v|rm|rmvb|mov|mkv|m3u8|dv|m4v|mts|ogg|webm)$";
    private final static Pattern VIDEO_FILENAME_PATTERN = Pattern.compile(VIDEO_FILENAME_REGEX);

    private final static String COMMON_FILE_SUFFIX_REGEX = "(rar|zip|txt|doc|docx|pdf|jpg|png|md|xls|xlsx|ppt|pptx|tar|gz)";
    private final static Pattern COMMON_FILE_SUFFIX_PATTERN = Pattern.compile(COMMON_FILE_SUFFIX_REGEX);

    private final static String MODBUS_RW_REGEX = "^[A-Fa-f0-9]{14}";
    private final static Pattern MODBUS_RW_PATTERN = Pattern.compile(MODBUS_RW_REGEX);

    private final static String TAGS_REGEX = "^[\\u4E00-\\u9FA5\\uF900-\\uFA2Da-zA-Z]+(,[\\u4E00-\\u9FA5\\uF900-\\uFA2Da-zA-Z]+)*$";
    private final static Pattern TAGS_PATTERN = Pattern.compile(TAGS_REGEX);

    private final static String ESCAPE_REGEX_REGEX = "([\\\\|()\\[\\]{}^$*+?.\\-])";
    private final static String DROP_REGEX_REGEX = "[\\\\|()\\[\\]{}^$*+?.\\-]";
    private final static Pattern DROP_REGEX_PATTERN = Pattern.compile(DROP_REGEX_REGEX);

    /**
     * 检查字符串是否中英文或数字
     *
     * @param text 目标字符串
     * @return 是否中英文或数字
     */
    public static boolean isChineseOrAlphabetOrDigit(String text) {
        if (null == text || text.isEmpty()) {
            return false;
        }
        return CHINESE_ALPHABET_DIGIT_PATTERN.matcher(text).matches();
    }

    /**
     * 检查手机号码合法性(大陆号码或香港号码均可).
     *
     * @param number 手机号码
     * @return 是否合法
     */
    public static boolean isPhoneNumberLegal(String number) {
        return isInlandPhoneNumberLegal(number) || isHKPhoneNumberLegal(number);
    }

    /**
     * 检查大陆手机号码合法性.
     * <br>
     * 大陆手机号码11位数，匹配格式：前三位固定格式+后8位任意数<br>
     * 此方法中前三位格式有： 13+任意数 15+除4的任意数 18+任意数 17+除9的任意数 147
     *
     * @param number 手机号码
     * @return 是否合法
     */
    public static boolean isInlandPhoneNumberLegal(String number) {
        if (null == number || number.isEmpty()) {
            return false;
        }
        return INLAND_PHONE_PATTERN.matcher(number).matches();
    }

    /**
     * 检查香港手机号码合法性.
     * <br>
     * 香港手机号码8位数，5|6|8|9开头+7位任意数
     *
     * @param number 手机号码
     * @return 是否合法
     */
    public static boolean isHKPhoneNumberLegal(String number) {
        if (null == number || number.isEmpty()) {
            return false;
        }
        return HK_PHONE_PATTERN.matcher(number).matches();
    }

    /**
     * 检查电子邮箱地址合法性
     *
     * @param email 电子邮箱地址
     * @return 是否合法
     */
    public static boolean isEmailLegal(String email) {
        if (null == email || email.isEmpty()) {
            return false;
        }
        return EmailValidator.getInstance().isValid(email);
    }

    /**
     * 检查MAC地址的合法性(6字节中划线)
     *
     * @param mac MAC地址
     * @return 是否合法
     */
    public static boolean isMacAddressLegal(String mac) {
        if (null == mac || mac.length() == 0) {
            return false;
        }
        return MAC_ADDRESS_PATTERN.matcher(mac).matches();
    }

    /**
     * 检查IP地址是否合法
     *
     * @param ip IP地址
     * @return 是否合法
     */
    public static boolean isIpAddressLegal(String ip) {
        if (null == ip || ip.isEmpty()) {
            return false;
        }
        return IP_ADDRESS_PATTERN.matcher(ip).matches();
    }

    /**
     * 检查域名是否合法
     *
     * @param domain 域名
     * @return 是否合法
     */
    public static boolean isDomainLegal(String domain) {
        if (null == domain || domain.isEmpty()) {
            return false;
        }
        return DomainValidator.getInstance().isValid(domain);
    }

    /**
     * 检查网址是否合法
     *
     * @param url 网址
     * @return 是否合法
     */
    public static boolean isUrlLegal(String url) {
        if (null == url || url.isEmpty()) {
            return false;
        }
        return UrlValidator.getInstance().isValid(url);
    }

    /**
     * 检查中国身份证号码是否合法
     *
     * @param number 身份证号码
     * @return 是否合法
     */
    public static boolean isChineseIdCardNumberLegal(String number) {
        if (null == number || number.isEmpty()) {
            return false;
        }
        return IDCARD_CN_PATTERN.matcher(number).matches();
    }

    /**
     * 检查以#开头的颜色字符串合法性(6位16进制)
     *
     * @param color 颜色字符串
     * @return 是否合法
     */
    public static boolean isColorStringLegal(String color) {
        if (null == color || color.isEmpty()) {
            return false;
        }
        return COLOR_STRING_PATTERN.matcher(color).matches();
    }

    /**
     * 验证文件名是否视频文件(忽略后缀大小写)
     *
     * @param filename 文件名
     * @return 是否视频文件
     */
    public static boolean isVideoFilename(String filename) {
        if (null == filename || filename.isEmpty()) {
            return false;
        }
        return VIDEO_FILENAME_PATTERN.matcher(filename).matches();
    }

    /**
     * 验证文件名是否为常见文件(忽略后缀大小写)
     *
     * @param suffix 文件扩展名
     * @return 是否常见文件
     */
    public static boolean isCommonFilename(String suffix) {
        if (null == suffix || suffix.isEmpty()) {
            return false;
        }
        return COMMON_FILE_SUFFIX_PATTERN.matcher(suffix).matches();
    }

    /**
     * 验证Modbus读/写命令合法性
     *
     * @param text Modbus读/写命令
     * @return 是否合法
     */
    public static boolean isModbusReadWriteCommandLegal(String text) {
        if (null == text || text.isEmpty()) {
            return false;
        }
        return MODBUS_RW_PATTERN.matcher(text).matches();
    }

    /**
     * 验证以逗号分隔的标签文字合法性
     *
     * @param tags 以逗号分隔的标签文字
     * @return 是否合法
     */
    public static boolean isTagsLegal(String tags) {
        if (null == tags || tags.isEmpty()) {
            return false;
        }
        return TAGS_PATTERN.matcher(tags).matches();
    }

    /**
     * 转义字符串中的正则表达式元字符
     *
     * @param text 需要转义元字符的字符串
     * @return 转义后的结果
     */
    public static String escapeRegexCharacter(String text) {
        if (null == text || text.length() == 0) {
            return text;
        }
        return text.replaceAll(ESCAPE_REGEX_REGEX, "\\\\$1");
    }

    /**
     * 去除文字中的正则表达式元字符
     *
     * @param text 需要去除正则元字符的字符串
     * @return 去除后的结果
     */
    public static String dropRegexCharacter(String text) {
        if (null == text || text.length() == 0) {
            return text;
        }
        return DROP_REGEX_PATTERN.matcher(text).replaceAll("").trim();
    }
}
